Na zbiorze danych clustering_R3.csv przetestujemy jeszcze inne dwie metody klasteryzacji. W zbiorze znajdują się trzy kolumny liczb, które można przedstawić punktami na układzie współrzędnych.
dane_oryg <- read.csv("../../clustering_R3.csv")
head(dane_oryg)
## X1 X2 X3
## 1 152.0780 197.9104 1.0957074
## 2 145.5205 202.1280 2.7388257
## 3 155.4413 198.1227 0.6404565
## 4 150.3891 206.8084 0.6864856
## 5 149.8632 205.4175 3.5558137
## 6 142.4108 208.9581 3.3838489
tail(dane_oryg)
## X1 X2 X3
## 995 357.6517 112.91781 17.151268
## 996 327.0585 95.04242 5.819534
## 997 379.8715 118.62044 13.329955
## 998 386.3637 97.26560 8.635707
## 999 331.2692 100.62328 6.228514
## 1000 359.1198 99.95350 20.211148
plot_ly(x=dane_oryg$X1, y=dane_oryg$X2, z=dane_oryg$X3, type="scatter3d", mode="markers", size=1)
plot(dane_oryg)
Wymiary są bardzo różnego zasięgu, więc przed pracą należałoby je przeskalować.
dane <- dane_oryg
for (x in 1:3)
dane[,x] <- scale(dane[,x])
head(dane)
## X1 X2 X3
## 1 -0.7624251 1.024041 -0.9093166
## 2 -0.8191723 1.124547 -0.5665699
## 3 -0.7333199 1.029100 -1.0042798
## 4 -0.7770403 1.236079 -0.9946783
## 5 -0.7815912 1.202935 -0.3961501
## 6 -0.8460827 1.287306 -0.4320212
tail(dane)
## X1 X2 X3
## 995 1.0165666 -1.0013201 2.43979683
## 996 0.7518192 -1.4272881 0.07605107
## 997 1.2088514 -0.8654271 1.64268923
## 998 1.2650339 -1.3743100 0.66349137
## 999 0.7882578 -1.2942968 0.16136251
## 1000 1.0292707 -1.3102576 3.07807325
Do przedstawienia wyników klasteryzacji definiuję sobie funkcję:
wykres <- function(da, q) {
kolory <- unique(q)
rbow <- rainbow(length(kolory))
if (0 %in% kolory){
q[q==0] <- max(kolory)+1
rbow <- c(rainbow(length(kolory)-1), "#000000FF")
}
fig <- plot_ly(x=da$X1, y=da$X2, z=da$X3,
color=q, colors=rbow,
type="scatter3d", mode="markers",
size=1)
fig
}
W przeciwieństwie do metod z pracy domowej nr 5 oraz tej, która jeszcze się pojawi, DBSCAN samowolnie wyznacza liczbę klastrów do podzielenia danych. Problemem może jednak być prawidłowy dobór parametrów ε i minPts. Udało mi się te wartości samodzielnie dobrać w taki sposób, żeby podział na klastry wyglądał możliwie “naturalnie”, ale najpierw przedstawię sposób estymacji proponowany przez, ekhem, fachowców.
Parametr minPts powinien być większy od liczby wymiarów o co najmniej 1, zatem w tym wypadku minimum wynosi 4.
Epsilon należy wyznaczyć bardziej doświadczalnie. Proponowaną metodą jest przedstawienie na wykresie odległości każdego punktu od k-tego najbliższego sąsiada, posortowanych od największej do najmniejszej, gdzie k = minPts-1. Optymalna wartość epsilona zostaje wyznaczona w miejscu “zgięcia łokcia”.
Do obliczenia k najbliższych sąsiadów (co jest tutaj czymś innym, niż dobrze nam znany model ML) używam pakietu FNN.
knn_3 <- get.knn(dane, k=3)
plot(1:1000, sort(knn_3[[2]][,3], decreasing=T), xlab="3NN", ylab="dystans")
Tym razem pozwolę sobie przyjąć miejsce zgięcia na oko, bez obliczeń obecnych poprzednim razem. Tym samym biorę ε = 0,25.
Niżej wynik klasteryzacji, obliczony na skalowanych danych, ale nałożony już na oryginalne. Czarne punkty nie zostały przyporządkowane do żadnego skupienia:
dbs <- dbscan(dane, 0.25, 4)
clu0 <- dbs$cluster
wykres(dane_oryg, clu0)
Parametry, które udało mi się ręcznie ustalić jako te optymalne, to tymczasem ε = 0,4 i minPts = 3.
dbs2 <- dbscan(dane, 0.4, 3)
clu1 <- dbs2$cluster
wykres(dane_oryg, clu1)
Tutaj najpierw wybieram liczbę klastrów. Tak jak dwa tygodnie temu, zastosuję fviz_nbclust z pakietu factoextra.
fviz_nbclust(dane, kmeans, method="silhouette")
Wskazaną liczbą klastrów jest 2. GMM nie przyporządkowuje od razu punktów do klastrów, a jedynie wyznacza prawdopodobieństwo, z jakim punkty należą do każdego z nich. Wciąż, można na podstawie tego szybko uzyskać optymalny podział.
gmm <- GMM(dane, gaussian_comps=2)
clu2 <- apply(gmm$Log_likelihood, 1, which.max)
wykres(dane_oryg, clu2)
Do porównania jakości klasteryzacji zastosuję współczynnik Silhouette i indeks Daviesa–Bouldina. W skrócie, współczynnik Silhouette daje informację, na ile podobne obserwacje są do swoich klastrów w porównaniu do innych. Miara przyjmuje wartości od -1 do 1, gdzie im wyższa wartość, tym mocniejsze przywiązanie obserwacji do jej skupienia. Indeks Daviesa-Bouldina natomiast ocenia klasteryzację na podstawie wartości i cech wywodzących się ze zbioru danych.
Jako reprezentację wyników DBSCAN wykorzystam podział dokonany z ręcznymi parametrami (0,4 i 3).
staty1 <- cluster.stats(dist(dane), clu1)
staty2 <- cluster.stats(dist(dane), clu2)
# współczynniki dla klastrów i średni współczynnik dla całego podziału
staty1$clus.avg.silwidths
## 1 2 3 4
## 0.7993158 0.8079347 0.3178257 0.3533559
staty1$avg.silwidth
## [1] 0.5700917
staty2$clus.avg.silwidths
## 1 2
## 0.5267710 0.7807689
staty2$avg.silwidth
## [1] 0.65377
db1 <- index.DB(dane, clu1)
db2 <- index.DB(dane, clu2)
db1$DB
## [1] 1.065152
db2$DB
## [1] 0.6145745
Wyniki są dosyć nieoczywiste. Metoda GMM daje średnio lepszy współczynnik Silhouette, ale o dużo więcej wyższy indeks Daviesa-Bouldina osiągnęła metoda DBSCAN. Co więcej, biorąc pod uwagę mniejsze zautomatyzowanie DBSCAN, czyli że użytkownik sam wybiera parametry i może nią osiągnąć bardziej “pożądane” wyniki, to tę metodę wolałbym wyróżnić.
Oświadczam, że niniejsza praca stanowiąca podstawę do uznania osiągnięcia efektów uczenia się z przedmiotu Wstęp do uczenia maszynowego została wykonana przeze mnie samodzielnie.